#include "stm32f10x.h"    
#include "freertos.h"
#include "task.h"
#include "queue.h"
#include "Delay.h"

#include <string.h>

#include "USART_Config.h"
#include "ESP01s_Control.h"
#include "HC05_Control.h"
#include "LED_Init.h"
#include "Buzzer_Init.h"

#define QUEUE_LENGTH 16	 					// 队列长度
#define ITEM_SIZE sizeof(USART_Message_t)	// 队列项大小
QueueHandle_t xQueue;

void USART_Handler(void);
void vTask_ESP01s_Controller(void *arg);
void vTask_ESP01s_Heartbeat(void *arg);

/*
// ========== 发文表述 ==========
//	 1. 查过资料
	 2. 分享思路
	 3. 对不对
// ========== 1期内容 ==========
// - 1. ESP-01控制
		【应该没什么大问题，等芯片到达以后测试就可以啦】
		- 连接网络
		- 结构体设置ESP-01状态，实现开启与关闭连接（“+++”透传使用USARTSendBuffer，通过FLAG切换状态，测试效果）
		- 已经确认wifi`连接时，自动联网
// √ 2. 服务器实现与手机通信
		【IP：47.111.20.8，root, ABC12345】
		- 手机端获取正确的通信格式
		- 服务器根据PacketID区分来源（STM32/手机/其他）
		- 修改手机的通信报文
// √ 3. 服务器超时踢出功能
		- 使用FreeRTOS的 xTaskCreate + vTaskDelay；
		- 实现STM32的每分钟心跳包
//   4. 设备状态转发
		- 定义LED/蜂鸣器控制结构体
		- 实现LED/蜂鸣器设备状态报文
		- 增加OLED显示状态
// √ 5. STM32硬件控制
		- 初始化LED/蜂鸣器GPIO
		- 将硬件操作封装成函数
// √ 6. 手机客户端接受信息
		- 在服务器添加客户端管理列表
		- 实现手机连接服务器	
// × 7. 修改消息格式，减少发送格式错误，避免粘包与半包
		【未完全修改，修改了发送格式USART_SendBuffer，未修改粘包与半包，发现收发消息逻辑都要改，太懒了，小项目还能凑活用】
		- 中断发送与接收分开处理
		- 将消息改为小火车：结构体+数据两次发送
//   8. 增加蓝牙，传向ESP-01

// ========== 2期内容 ==========
//   1. 增加服务器日志功能
		- 普通日志文件
		- 日志严重程度分类INFO，ERROR，向上兼容
//   2. 增加服务器配置文件功能
//   3. 增加ADC传感器
		- 扫描端口，以结构体保存Buzzer, ADC设备状态
		- 温度云端处理
		- 报警

// ========== 3期内容 ==========
//   1. 将蓝牙、WIFI的账号密码记入STM32 flush中
		- 看门狗复位
		- 自动连接蓝牙
		- （ESP分支-是否连接-是否有flag）自动连接WIFI，发送AT指令，询问联网状态
		
// ========== 4期内容 ==========
//   1. 增加外存flush

// ========== 拓展内容 ==========
//   1. 增加用户通过网页端向STM32发送指令，控制设备
	【设置按钮点击，随便乱输容易被黑掉】
	- 服务器端发送代码
	- 用户端发送代码
	- 用户端设置按钮

*/

int main(void){
	Delay_Init();						// 初始化 Delay函数
	
	USART_Pin_Init(&USART1_Cfg);  		// 初始化 USB_TO_TTL
	USART_Pin_Init(&USART2_Cfg);  		// 初始化 ESP01s
//	USART_Pin_Init(&USART3_Cfg);  		// 初始化 HC05
	USART_NVIC_Init(&USART1_Cfg);  		// 初始化 中断源优先级
	USART_NVIC_Init(&USART2_Cfg);  		
	
	LED_Init();
	Buzzer_Init();
	USART_Handler();
//	HC05_Control();						// 开始蓝牙<扫描不到我的设备，放弃了>
	
	ESP_Status();						// 上电以后自动查询ESP状态，通常会进行自动连接与定时发送消息
	
	xQueue = xQueueCreate(QUEUE_LENGTH,  ITEM_SIZE);

	xTaskCreate(vTask_ESP01s_Controller, "vTask_LED_Controller", configMINIMAL_STACK_SIZE * 4, NULL, 2, NULL);	
	xTaskCreate(vTask_ESP01s_Heartbeat, "vTask_ESP01s_Heartbeat", configMINIMAL_STACK_SIZE * 2, NULL, 1, NULL);	
	vTaskStartScheduler();					// 启动调度器，调试到此处按F11
	
	while(1);								// 程序不应执行到这里
}

// 串口任务
void USART_Handler(void) {
	Delay_ms(1000);
	
    const char *hello_str = 
        "ESP01s Controller COMMANDS:\r\n"
	    "  ESPSTART\r\n"
		"  ESPSEND\r\n"
        "  ESPSTATUS\r\n"
        "  ESPEND\r\n"
        "-----------------------\r\n"
        "Waiting for input...\r\n";

    USART_Message_t msg = {
		.source_id = 2,
		.device_id = DEVICE_USART,
		.len = strlen(hello_str),
	};

    memcpy(msg.data, hello_str, (msg.len < MAX_STR_LEN) ? msg.len : MAX_STR_LEN-1);		// 适合二进制数据
    
    msg.data[MAX_STR_LEN-1] = '\0';  

    USART_printf(&USART1_Cfg, (char*)msg.data);
}

// USART1控制任务
void vTask_ESP01s_Controller(void *arg) {	
	USART_Message_t msg;
	char msg_rev[MAX_STR_LEN] = {0};
	
    while(1) {		
		if(xQueueReceive(xQueue, &msg, 500) == pdPASS){			// 写portMAX_DELAY会被持续阻塞
//			if(msg.source_id == 1 || (msg.source_id == 2 && ESP_state == ESP_state_CONNECT)){
			if(msg.source_id == 1){
				strcpy(msg_rev, (const char*)msg.data);	
				if(strncmp(msg_rev, "ESPSTATUS", 9) == 0){		
					ESP_Status();  
				}				
				else if(strncmp(msg_rev, "ESPSEND", 7) == 0){		
					ESP_SendPacket();
				}	
				else if(strncmp(msg_rev, "ESPSTART", 8) == 0){	
					ESP_index = 0;
					ESP_state = ESP_state_START;
					ESP_StControl();  
				}	
				else if(strncmp(msg_rev, "ESPEND", 6) == 0){		
					ESP_index = 0;
					ESP_state = ESP_state_END;
					ESP_EdControl();  
				}
				
				USART_printf(&USART1_Cfg, "USART1 Receive the str: %s \r\n", (msg_rev));	
				memset(msg_rev, sizeof(msg_rev), 0);
			}
			if(msg.source_id == 2){
//				size_t copy_len = (msg.len < MAX_STR_LEN-1) ? msg.len : MAX_STR_LEN-1;		    // 安全拷贝数据
//				memcpy(msg_rev, msg.data, copy_len);
//				msg_rev[copy_len] = '\0';  				// 确保字符串终止
				strcpy(msg_rev, (const char*)msg.data);
				
				if(strncmp(msg_rev, "OK", 2) == 0 && ESP_state == ESP_state_START){							// 启动且未联网，则自动联网
					ESP_StControl();  
				}	
				else if(strncmp(msg_rev, "ready", 5) == 0 && ESP_state == ESP_state_START){					// 启动且已联网，则自动转为透传并进行TCP连接
					ESP_index = ESP_state_CONNECT;
					ESP_StControl();  
				}	
				else if(strncmp(msg_rev, "HTTP/1.1 200 OK", 15) == 0 && ESP_state == ESP_state_START){		// 启动且能收到消息，则自动转为透传模式
					ESP_index = ESP_STATE_TRANSPARENT;
				}
				else if(strncmp(msg_rev, "OK", 2) == 0 && ESP_state == ESP_state_END){						// 收到关闭信息，则关闭ESP
					ESP_EdControl();  
				}						

				USART_printf(&USART1_Cfg, "USART2 Receive the str: %s \r\n", (msg_rev));	// 注意此处输出到屏幕，而非ESP-01
				memset(msg_rev, sizeof(msg_rev), 0);


			}
			if(msg.source_id == 3){
			}
		}
		vTaskDelay(100);
	}
}

void vTask_ESP01s_Heartbeat(void *arg){
	while(1){
		if(ESP_state == ESP_STATE_TRANSPARENT){
			ESP_SendPacket();
		}
		vTaskDelay(30000);
	}
}
